package org.zeqp.chatAI.redis;

import com.alibaba.fastjson2.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;

import java.util.*;


/**
 * 
 * @ClassName RedisRepository
 * @author BOOM
 * @date 2018/10/12
 *
 */
@Component
public class RedisRepository {

	@Autowired
	@Qualifier("objectRedisTemplate")
	RedisTemplate<String, ?> redisTemplate;

	/**
	 * 验证key是否存在
	 * 
	 * @param key
	 * @return existenct:true,non-existent:false
	 */
	public boolean exists(String key) {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Boolean exists = connection.exists(serializer.serialize(key));
				return exists;
			}
		});
	}

	/**
	 * 删除一个key
	 * 
	 * @param key
	 * @return long
	 */
	public long del(String key) {
		return redisTemplate.execute(new RedisCallback<Long>() {
			@Override
			public Long doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Long del = connection.del(serializer.serialize(key));
				return del;
			}
		});
	}
	
	/**
	 * 删除一个key
	 * 
	 * @param key
	 * @return long
	 */
	public long del(Integer db, String key) {
		return redisTemplate.execute(new RedisCallback<Long>() {
			@Override
			public Long doInRedis(RedisConnection connection) throws DataAccessException {
				connection.select(db);
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Long del = connection.del(serializer.serialize(key));
				return del;
			}
		});
	}

	/**
	 * 获取当前数据库中key的数目
	 * 
	 * @return long
	 */
	public long dbSize() {
		return redisTemplate.execute(new RedisCallback<Long>() {
			@Override
			public Long doInRedis(RedisConnection connection) throws DataAccessException {
				Long dbSize = connection.dbSize();
				return dbSize;
			}
		});
	}

	/**
	 * 设置key的过期时间
	 * 
	 * @param key
	 * @param seconds
	 *            s
	 * @return success:true,fail:false
	 */
	public boolean expire(String key, long seconds) {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Boolean expire = connection.expire(serializer.serialize(key), seconds);
				return expire;
			}
		});
	}

	public boolean expire(int db, String key, long seconds) {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				connection.select(db);
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Boolean expire = connection.expire(serializer.serialize(key), seconds);
				return expire;
			}
		});
	}

	/**
	 * 清空当前DB库中所有key，慎用
	 * 
	 * @return success:true,fail:false
	 */
	public boolean flushDb() {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				connection.flushDb();
				return true;
			}
		});
	}

	/**
	 * 清空所有库中的key，慎用
	 * 
	 * @return success:true,fail:false
	 */
	public boolean flushAll() {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				connection.flushAll();
				return true;
			}
		});
	}

	/**
	 * 设置key-value
	 * 
	 * @param key
	 * @param value
	 * @return success:true,fail:false
	 */
	public boolean set(String key, Object value) {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				String val = JSON.toJSONString(value);
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				connection.set(serializer.serialize(key), serializer.serialize(val));
				return true;
			}
		});
	}

	/**
	 * 获取一个key
	 * 
	 * @param key
	 * @param clz
	 * @return V
	 */
	@SuppressWarnings("unchecked")
	public <V> V get(String key, Class<V> clz) {
		return redisTemplate.execute(new RedisCallback<V>() {
			@Override
			public V doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				byte[] bs = connection.get(serializer.serialize(key));
				String deserialize = serializer.deserialize(bs);
				if (clz.getName().equals("java.lang.String")) {
					return (V) deserialize;
				}
				V parseObject = JSON.parseObject(deserialize, clz);
				return parseObject;
			}
		});
	}
	
	@SuppressWarnings("unchecked")
	public <V> V get(String key) {
		return redisTemplate.execute(new RedisCallback<V>() {
			@Override
			public V doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				byte[] bs = connection.get(serializer.serialize(key));
				String deserialize = serializer.deserialize(bs);
				return (V) deserialize;
			}
		});
	}

	@SuppressWarnings("unchecked")
	public <V> V get(Integer db, String key, Class<V> clz) {
		return redisTemplate.execute(new RedisCallback<V>() {
			@Override
			public V doInRedis(RedisConnection connection) throws DataAccessException {
				connection.select(db);
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				byte[] bs = connection.get(serializer.serialize(key));
				String deserialize = serializer.deserialize(bs);
				if (clz.getName().equals("java.lang.String")) {
					return (V) deserialize;
				}
				V parseObject = JSON.parseObject(deserialize, clz);
				return parseObject;
			}
		});
	}

	/**
	 * 批量获取key
	 * 
	 * @param clz
	 * @param keys
	 * @return List
	 */
	public <V> List<V> mGet(Class<V> clz, String... keys) {
		return redisTemplate.execute(new RedisCallback<List<V>>() {
			@SuppressWarnings("unchecked")
			@Override
			public List<V> doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				byte[][] key = new byte[keys.length][];
				int i = 0;
				for (String string : keys) {
					key[i++] = serializer.serialize(string);
				}
				List<byte[]> mGet = connection.mGet(key);
				List<V> list = new ArrayList<V>();
				for (byte[] bs : mGet) {
					if (clz.getName().equals("java.lang.String")) {
						list.add((V) serializer.deserialize(bs));
					}
					list.add(JSON.parseObject(serializer.deserialize(bs), clz));
				}
				return list;
			}
		});
	}

	/**
	 * 添加一个key的同时验证key是否存在，不存在添加key-value，存在返回false
	 * 
	 * @param key
	 * @param value
	 * @return success:true,fail:false
	 */
	public boolean setNX(String key, Object value) {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Boolean setNX = connection.setNX(serializer.serialize(key),
						serializer.serialize(JSON.toJSONString(value)));
				return setNX;
			}
		});
	}

	/**
	 * 添加一个key-value，同时添加过期时间
	 * 
	 * @param key
	 * @param value
	 * @param seconds
	 *            s
	 * @return success:true,fail:false
	 */
	public boolean setEX(String key, Object value, long seconds) {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				connection.setEx(serializer.serialize(key), seconds, serializer.serialize(JSON.toJSONString(value)));
				return true;
			}
		});
	}

	public boolean setEX(int db, String key, Object value, long seconds) {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				connection.select(db);
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				connection.setEx(serializer.serialize(key), seconds, serializer.serialize(JSON.toJSONString(value)));
				return true;
			}
		});
	}

	/**
	 * 批量添加key-value
	 * 
	 * @param map
	 * @return success:true,fail:false
	 */
	public boolean mSet(Map<String, Object> map) {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Map<byte[], byte[]> tuple = new HashMap<byte[], byte[]>();
				for (Map.Entry<String, Object> entry : map.entrySet()) {
					tuple.put(serializer.serialize(entry.getKey()),
							serializer.serialize(JSON.toJSONString(entry.getValue())));
				}
				connection.mSet(tuple);
				return true;
			}
		});
	}

	/**
	 * 批量添加key-value的同时验证key是否存在，不存在直接添加，存在返回false
	 * 
	 * @param map
	 * @return success:true,fail:false
	 */
	public boolean mSetNX(Map<String, Object> map) {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Map<byte[], byte[]> tuple = new HashMap<byte[], byte[]>();
				for (Map.Entry<String, Object> entry : map.entrySet()) {
					tuple.put(serializer.serialize(entry.getKey()),
							serializer.serialize(JSON.toJSONString(entry.getValue())));
				}
				Boolean mSetNX = connection.mSetNX(tuple);
				return mSetNX;
			}
		});
	}

	/**
	 * 在list为key的尾部添加value
	 * 
	 * @param key
	 * @param value
	 * @return list长度
	 */
	public long rPush(String key, Object value) {
		return redisTemplate.execute(new RedisCallback<Long>() {
			@Override
			public Long doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Long rPush = connection.rPush(serializer.serialize(key),
						serializer.serialize(JSON.toJSONString(value)));
				return rPush;
			}
		});
	}

	/**
	 * 在list为key的头部添加value
	 * 
	 * @param key
	 * @param value
	 * @return list长度
	 */
	public long lPush(String key, Object value) {
		return redisTemplate.execute(new RedisCallback<Long>() {
			@Override
			public Long doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Long lPush = connection.lPush(serializer.serialize(key),
						serializer.serialize(JSON.toJSONString(value)));
				return lPush;
			}
		});
	}

	/**
	 * 返回list的长度
	 * 
	 * @param key
	 * @return long
	 */
	public long lLen(String key) {
		return redisTemplate.execute(new RedisCallback<Long>() {
			@Override
			public Long doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Long lLen = connection.lLen(serializer.serialize(key));
				return lLen;
			}
		});
	}

	/**
	 * 返回名称为key的list中start至end之间的元素（下标从0开始）
	 * 
	 * @param key
	 * @param start
	 * @param end
	 * @param clz
	 * @return List
	 */
	public <V> List<V> lRange(String key, long start, long end, Class<V> clz) {
		return redisTemplate.execute(new RedisCallback<List<V>>() {
			@SuppressWarnings("unchecked")
			@Override
			public List<V> doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				List<byte[]> lRange = connection.lRange(serializer.serialize(key), start, end);
				List<V> list = new ArrayList<V>();
				for (byte[] bs : lRange) {
					if (clz.getName().equals("java.lang.String")) {
						list.add((V) serializer.deserialize(bs));
					} else {
						list.add(JSON.parseObject(serializer.deserialize(bs), clz));
					}
				}
				return list;
			}
		});
	}

	/**
	 * 返回名称为key的list中index位置的元素
	 * 
	 * @param key
	 * @param index
	 * @param clz
	 * @return V
	 */
	public <V> V lIndex(String key, long index, Class<V> clz) {
		return redisTemplate.execute(new RedisCallback<V>() {
			@SuppressWarnings("unchecked")
			@Override
			public V doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				byte[] lIndex = connection.lIndex(serializer.serialize(key), index);
				if (clz.getName().equals("java.lang.String")) {
					return (V) serializer.deserialize(lIndex);
				} else {
					return JSON.parseObject(serializer.deserialize(lIndex), clz);
				}
			}
		});
	}

	/**
	 * 给名称为key的list中index位置的元素赋值为value
	 * 
	 * @param key
	 * @param index
	 * @param value
	 * @return success:true,fail:false
	 */
	public boolean lSet(String key, long index, Object value) {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				connection.lSet(serializer.serialize(key), index, serializer.serialize(JSON.toJSONString(value)));
				return true;
			}
		});
	}

	/**
	 * 删除count个名称为key的list中值为value的元素。 count为0，删除所有值为value的元素， count>0
	 * 从头至尾删除|count|个值为value的元素， count<0 从尾到头删除|count|个值为value的元素。
	 * 
	 * @param key
	 * @param count
	 * @param value
	 * @return long
	 */
	public long lRem(String key, long count, Object value) {
		return redisTemplate.execute(new RedisCallback<Long>() {
			@Override
			public Long doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Long lRem = connection.lRem(serializer.serialize(key), count,
						serializer.serialize(JSON.toJSONString(value)));
				return lRem;
			}
		});
	}

	/**
	 * 返回并删除名称为key的list中的首元素
	 * 
	 * @param key
	 * @param clz
	 * @return V
	 */
	public <V> V lPop(String key, Class<V> clz) {
		return redisTemplate.execute(new RedisCallback<V>() {
			@SuppressWarnings("unchecked")
			@Override
			public V doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				byte[] lPop = connection.lPop(serializer.serialize(key));
				if (clz.getName().equals("java.lang.String")) {
					return (V) serializer.deserialize(lPop);
				}
				return JSON.parseObject(serializer.deserialize(lPop), clz);
			}
		});
	}

	/**
	 * 返回并删除名称为key的list中的尾元素
	 * 
	 * @param key
	 * @param clz
	 * @return V
	 */
	public <V> V rPop(String key, Class<V> clz) {
		return redisTemplate.execute(new RedisCallback<V>() {
			@SuppressWarnings("unchecked")
			@Override
			public V doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				byte[] rPop = connection.rPop(serializer.serialize(key));
				if (clz.getName().equals("java.lang.String")) {
					return (V) serializer.deserialize(rPop);
				}
				return JSON.parseObject(serializer.deserialize(rPop), clz);
			}
		});
	}

	/**
	 * 返回并删除名称为srckey的list的尾元素，并将该元素添加到名称为dstkey的list的头部
	 * 
	 * @param srcKey
	 * @param dstKey
	 * @param clz
	 * @return V
	 */
	public <V> V rpoplpush(String srcKey, String dstKey, Class<V> clz) {
		return redisTemplate.execute(new RedisCallback<V>() {
			@SuppressWarnings("unchecked")
			@Override
			public V doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				byte[] rPopLPush = connection.rPopLPush(serializer.serialize(srcKey), serializer.serialize(dstKey));
				if (clz.getName().equals("java.lang.String")) {
					return (V) serializer.deserialize(rPopLPush);
				}
				return JSON.parseObject(serializer.deserialize(rPopLPush), clz);
			}
		});
	}

	/**
	 * 向名称为key的hash中添加元素field<—>value
	 * 
	 * @param key
	 * @param field
	 * @param value
	 * @return success:true,fail:false
	 */
	public boolean hSet(String key, String field, Object value) {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Boolean hSet = connection.hSet(serializer.serialize(key), serializer.serialize(field),
						serializer.serialize(JSON.toJSONString(value)));
				return hSet;
			}
		});
	}

	/**
	 * 向名称为key的hash中添加元素field<—>value
	 * 
	 * @param key
	 * @param db
	 * @param field
	 * @param value
	 * @return success:true,fail:false
	 */
	public boolean hSet(Integer db, String key, String field, Object value) {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				connection.select(db);
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Boolean hSet = connection.hSet(serializer.serialize(key), serializer.serialize(field),
						serializer.serialize(JSON.toJSONString(value)));
				return hSet;
			}
		});
	}

	/**
	 * 返回名称为key的hash中field对应的value
	 * 
	 * @param key
	 * @param field
	 * @param clz
	 * @return V
	 */
	public synchronized <V> V hGet(String key, String field, Class<V> clz) {
		return redisTemplate.execute(new RedisCallback<V>() {
			@SuppressWarnings("unchecked")
			@Override
			public V doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				byte[] hGet = connection.hGet(serializer.serialize(key), serializer.serialize(field));
				if (clz.getName().equals("java.lang.String")) {
					return (V) serializer.deserialize(hGet);
				}
				return JSON.parseObject(serializer.deserialize(hGet), clz);
			}
		});
	}

	/**
	 * 返回名称为key的hash中field对应的value
	 * 
	 * @param key
	 * @param field
	 * @param clz
	 * @return V
	 */
	public synchronized <V> V hGet(Integer db, String key, String field, Class<V> clz) {
		return redisTemplate.execute(new RedisCallback<V>() {
			@SuppressWarnings("unchecked")
			@Override
			public V doInRedis(RedisConnection connection) throws DataAccessException {
				connection.select(db);
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				byte[] hGet = connection.hGet(serializer.serialize(key), serializer.serialize(field));
				if (clz.getName().equals("java.lang.String")) {
					return (V) serializer.deserialize(hGet);
				}
				return JSON.parseObject(serializer.deserialize(hGet), clz);
			}
		});
	}

	/**
	 * 返回名称为key的hash中field i对应的value
	 * 
	 * @param key
	 * @param clz
	 * @param fields
	 * @return List<V>
	 */
	public <V> List<V> hMget(String key, Class<V> clz, String... fields) {
		return redisTemplate.execute(new RedisCallback<List<V>>() {
			@SuppressWarnings("unchecked")
			@Override
			public List<V> doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				byte[][] field = new byte[fields.length][];
				int i = 0;
				for (String string : fields) {
					field[i++] = serializer.serialize(string);
				}
				List<byte[]> hMGet = connection.hMGet(serializer.serialize(key), field);
				List<V> list = new ArrayList<V>();
				for (byte[] bs : hMGet) {
					if (clz.getName().equals("java.lang.String")) {
						list.add((V) serializer.deserialize(bs));
					} else {
						list.add(JSON.parseObject(serializer.deserialize(bs), clz));
					}
				}
				return list;
			}
		});
	}

	/**
	 * 向名称为key的hash中添加元素field i<—>value i
	 * 
	 * @param key
	 * @param map
	 * @return success:true,fail:false
	 */
	public boolean hMset(String key, Map<String, Object> map) {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Map<byte[], byte[]> hashes = new HashMap<byte[], byte[]>();
				for (Map.Entry<String, Object> entry : map.entrySet()) {
					hashes.put(serializer.serialize(entry.getKey()),
							serializer.serialize(JSON.toJSONString(entry.getValue())));
				}
				connection.hMSet(serializer.serialize(key), hashes);
				return true;
			}
		});
	}

	/**
	 * 名称为key的hash中是否存在键为field的域
	 * 
	 * @param key
	 * @param field
	 * @return success:true,fail:false
	 */
	public boolean hExists(String key, String field) {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Boolean hExists = connection.hExists(serializer.serialize(key), serializer.serialize(field));
				return hExists;
			}
		});
	}

	/**
	 * 删除名称为key的hash中键为field的域
	 * 
	 * @param key
	 * @param fields
	 * @return long
	 */
	public long hdel(String key, String fields) {
		return redisTemplate.execute(new RedisCallback<Long>() {
			@Override
			public Long doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Long hDel = connection.hDel(serializer.serialize(key), serializer.serialize(fields));
				return hDel;
			}
		});
	}

	/**
	 * 删除名称为key的hash中键为field的域
	 * 
	 * @param key
	 * @param db
	 * @param fields
	 * @return long
	 */
	public long hdel(Integer db, String key, String fields) {
		return redisTemplate.execute(new RedisCallback<Long>() {
			@Override
			public Long doInRedis(RedisConnection connection) throws DataAccessException {
				connection.select(db);
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Long hDel = connection.hDel(serializer.serialize(key), serializer.serialize(fields));
				return hDel;
			}
		});
	}

	/**
	 * 返回名称为key的hash中元素个数
	 * 
	 * @param key
	 * @return long
	 */
	public long hlen(String key) {
		return redisTemplate.execute(new RedisCallback<Long>() {
			@Override
			public Long doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Long hLen = connection.hLen(serializer.serialize(key));
				return hLen;
			}
		});
	}

	/**
	 * 返回名称为key的hash中所有键
	 * 
	 * @param key
	 * @return List<String>
	 */
	public List<String> hkeys(String key) {
		return redisTemplate.execute(new RedisCallback<List<String>>() {
			@Override
			public List<String> doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Set<byte[]> hKeys = connection.hKeys(serializer.serialize(key));
				Set<String> set = new HashSet<>();
				for (byte[] bs : hKeys) {
					set.add(serializer.deserialize(bs));
				}
				List<String> arrayList = new ArrayList<>(set);
				return arrayList;
			}
		});
	}

	/**
	 * 返回名称为key的hash中所有键对应的value
	 * 
	 * @param key
	 * @param clz
	 * @return List<V>
	 */
	public <V> List<V> hvals(String key, Class<V> clz) {
		return redisTemplate.execute(new RedisCallback<List<V>>() {
			@SuppressWarnings("unchecked")
			@Override
			public List<V> doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				List<byte[]> hVals = connection.hVals(serializer.serialize(key));
				Set<V> set = new HashSet<>();
				for (byte[] bs : hVals) {
					if (clz.getName().equals("java.lang.String")) {
						set.add((V) serializer.deserialize(bs));
					} else {
						set.add(JSON.parseObject(serializer.deserialize(bs), clz));
					}
				}
				List<V> arrayList = new ArrayList<>(set);
				return arrayList;
			}
		});
	}

	/**
	 * 返回名称为key的hash中所有的键（field）及其对应的value
	 * 
	 * @param key
	 * @param clz
	 * @return Map<String, V>
	 */
	public <V> Map<String, V> hgetall(String key, Class<V> clz) {
		return redisTemplate.execute(new RedisCallback<Map<String, V>>() {
			@SuppressWarnings("unchecked")
			@Override
			public Map<String, V> doInRedis(RedisConnection connection) throws DataAccessException {
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Map<byte[], byte[]> hGetAll = connection.hGetAll(serializer.serialize(key));
				Map<String, V> map = new HashMap<>();
				for (Map.Entry<byte[], byte[]> entry : hGetAll.entrySet()) {
					if (clz.getName().equals("java.lang.String")) {
						map.put(serializer.deserialize(entry.getKey()), (V) serializer.deserialize(entry.getValue()));
					} else {
						map.put(serializer.deserialize(entry.getKey()),
								JSON.parseObject(serializer.deserialize(entry.getValue()), clz));
					}
				}
				return map;
			}
		});
	}

	/**
	 * 返回名称为key的hash中所有的键（field）及其对应的value
	 * 
	 * @param key
	 * @param db
	 * @param clz
	 * @return Map<String, V>
	 */
	public <V> Map<String, V> hgetall(Integer db, String key, Class<V> clz) {
		return redisTemplate.execute(new RedisCallback<Map<String, V>>() {
			@SuppressWarnings("unchecked")
			@Override
			public Map<String, V> doInRedis(RedisConnection connection) throws DataAccessException {
				connection.select(db);
				RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				Map<byte[], byte[]> hGetAll = connection.hGetAll(serializer.serialize(key));
				Map<String, V> map = new HashMap<>();
				for (Map.Entry<byte[], byte[]> entry : hGetAll.entrySet()) {
					if (clz.getName().equals("java.lang.String")) {
						map.put(serializer.deserialize(entry.getKey()), (V) serializer.deserialize(entry.getValue()));
					} else {
						map.put(serializer.deserialize(entry.getKey()),
								JSON.parseObject(serializer.deserialize(entry.getValue()), clz));
					}
				}
				return map;
			}
		});
	}

}
